package com.xh.bussiness.system.controller;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import com.mzlion.easyokhttp.HttpClient;
import com.qiniu.common.Zone;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.util.Auth;
import com.xh.bussiness.system.bean.dto.FileListBean;
import com.xh.core.bean.AjaxResult;
import com.xh.core.constant.AjaxResultConstant;
import com.xh.core.event.ConvertFileEvent;
import com.xh.core.properties.XhProperties;
import com.xh.bussiness.system.service.IFileListService;
import com.xh.core.util.DateUtils;
import com.xh.core.util.FileUtils;
import com.xh.core.util.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/*
 * @Author daiwei
 * @Description
 * @Date 2018/8/15 16:25
 **/
@Api(tags = "文件处理")
@RestController
@RequestMapping("/system/file")
public class FileController {

    @Autowired
    ApplicationContext applicationContext;
    @Autowired
    private XhProperties xhProperties;
    @Autowired
    private IFileListService fileListService;

    /**
     * 根据MD5判断文件是否已经存在
     *
     * @param md5
     * @return
     */
    @ApiOperation(value = "判断当前MD5值文件是否存在", notes = "判断当前MD5值文件是否存在")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "md5", value = "文件MD5值", required = true, dataType = "String"),
    })
    @PostMapping("/checkFileMd5Exist")
    public AjaxResult checkFileMd5Exist(String md5, HttpServletRequest request) {
        try {
            if (xhProperties.getUpload().getCheckMd5()) {
                FileListBean fileList = fileListService.queryFileList(md5);
                if (fileList != null) {
                    String filePath = request.getSession().getServletContext().getRealPath("/");
                    String relativePath = fileList.getFilePath();
                    filePath += relativePath;
                    File file = new File(filePath);
                    if (!file.exists()) {
                        return new AjaxResult(AjaxResultConstant.Result.SUCCESS, "", null);
                    }
                }
                return new AjaxResult(AjaxResultConstant.Result.SUCCESS, "", fileList);
            } else {
                return new AjaxResult(AjaxResultConstant.Result.SUCCESS, "", null);
            }
        } catch (Exception ex) {
            return new AjaxResult(AjaxResultConstant.Result.ERROR, ex.getMessage());
        }
    }

    /**
     * 获取七牛Token
     *
     * @param customPath
     * @param originalFilename
     * @return
     */
    @ApiOperation(value = "获取七牛Token", notes = "获取七牛Token")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "originalFilename", value = "源文件名", required = true, dataType = "String"),
            @ApiImplicitParam(name = "customPath", value = "自定义上传路径", required = false, dataType = "String")
    })
    @PostMapping("/getQiniuUploadToken")
    public AjaxResult getQiniuUploadToken(String customPath, String originalFilename) {
        try {
            String relativePath = "upload" + "/";
            if (!StringUtils.isEmpty(customPath)) {
                relativePath += customPath + "/";
            }
            Date now = new Date();
            relativePath += DateUtils.format(now, "yyyyMM") + "/";
            relativePath += DateUtils.format(now, "dd") + "/";

            String newFilename = FileUtils.randomRenameFilename(originalFilename);

            String savePath = relativePath + newFilename;

            Auth auth = Auth.create(xhProperties.getUpload().getQiniu().getAccessKey(), xhProperties.getUpload().getQiniu().getSecretKey());
            String upToken = auth.uploadToken(xhProperties.getUpload().getQiniu().getBucket(), savePath);

            JSONObject json = new JSONObject();
            json.put("key", savePath);
            json.put("upToken", upToken);
            return new AjaxResult(AjaxResultConstant.Result.SUCCESS, "", json);
        } catch (Exception ex) {
            return new AjaxResult(AjaxResultConstant.Result.ERROR, ex.getMessage());
        }
    }

    @ApiOperation(value = "批量删除七牛文件", notes = "批量删除七牛文件")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "files", value = "七牛文件路径集合", required = true, dataType = "String[]"),
    })
    @PostMapping("/deleteQiniuFiles")
    @ResponseBody
    public AjaxResult deleteQiniuFiles(String[] files) {
        try {
            Configuration cfg = new Configuration(Zone.zone0());
            Auth auth = Auth.create(xhProperties.getUpload().getQiniu().getAccessKey(), xhProperties.getUpload().getQiniu().getSecretKey());
            BucketManager bucketManager = new BucketManager(auth, cfg);

            BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
            batchOperations.addDeleteOp(xhProperties.getUpload().getQiniu().getBucket(), files);
            Response response = bucketManager.batch(batchOperations);
            /**
             BatchStatus[] batchStatusList = response.jsonToObject(BatchStatus[].class);

             for (int i = 0; i < files.length; i++) {
             BatchStatus status = batchStatusList[i];
             String key = files[i];
             }
             */
            return new AjaxResult(AjaxResultConstant.Result.SUCCESS, "");
        } catch (Exception ex) {
            return new AjaxResult(AjaxResultConstant.Result.ERROR, ex.getMessage());
        }
    }

    /**
     * 单文件上传
     *
     * @param file
     * @param request
     * @return
     */
    @ApiOperation(value = "单个文件上传", notes = "单个文件上传")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "file", value = "文件", required = true, dataType = "MultipartFile"),
    })
    @PostMapping("/uploadFile")
    public AjaxResult upload(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
        try {
            JSONObject result = new JSONObject();
            if (!file.isEmpty()) {
                String md5 = request.getParameter("md5");
                FileListBean fileList = null;
                if (!StringUtils.isEmpty(md5)) {
                    fileList = fileListService.queryFileList(md5);
                    if (fileList != null && xhProperties.getUpload().getCheckMd5()) {
                        String filePath = request.getSession().getServletContext().getRealPath("/");
                        String relativePath = fileList.getFilePath();
                        filePath += relativePath;
                        File oldFile = new File(filePath);
                        if (oldFile.exists()) {
                            result.put("originalFilename", file.getOriginalFilename());
                            result.put("savePath", fileList.getFilePath());
                            return new AjaxResult(AjaxResultConstant.Result.SUCCESS, "", result);
                        }
                    }
                }

                String uploadPath = request.getSession().getServletContext().getRealPath("/");
                String relativePath = "upload" + "/";
                String customPath = request.getParameter("path");
                if (!StringUtils.isEmpty(customPath)) {
                    relativePath += customPath + "/";
                }
                Date now = new Date();
                relativePath += DateUtils.format(now, "yyyyMM") + "/";
                relativePath += DateUtils.format(now, "dd") + "/";

                String newFilename = FileUtils.randomRenameFilename(file.getOriginalFilename());

                uploadPath += relativePath;
                result.put("oriFilename", file.getOriginalFilename());
                result.put("filePath", "/" + relativePath + newFilename);

                File saveFile = new File(uploadPath, newFilename);
                if (!saveFile.getParentFile().exists()) {
                    saveFile.getParentFile().mkdirs();
                }
                try {
                    BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(saveFile));
                    //out.write(file.getBytes());
                    InputStream is = file.getInputStream();
                    byte[] buffer = new byte[1024];
                    int i = -1;
                    while ((i = is.read(buffer)) != -1) {
                        out.write(buffer, 0, i);
                    }
                    out.flush();
                    out.close();

                    result.put("fileSize", file.getSize());
                    result.put("ext", Files.getFileExtension(file.getOriginalFilename().toLowerCase()));
                    try {
                        if (!StringUtils.isEmpty(md5)) {
                            if (fileList == null) {
                                fileList = new FileListBean();
                                fileList.setOriFilename(file.getOriginalFilename());
                                fileList.setFileMd5(md5);
                                fileList.setExt(Files.getFileExtension(file.getOriginalFilename().toLowerCase()));
                                fileList.setFileSize(file.getSize());
                                fileList.setFilePath("/" + relativePath + newFilename);
                                fileListService.insertObj(fileList);
                            } else {
                                fileList.setOriFilename(file.getOriginalFilename());
                                fileList.setFileMd5(md5);
                                fileList.setExt(Files.getFileExtension(file.getOriginalFilename().toLowerCase()));
                                fileList.setFileSize(file.getSize());
                                fileList.setFilePath("/" + relativePath + newFilename);
                                fileListService.updateObj(fileList);
                            }
                        }
                    } catch (Exception ex) {

                    }
                    applicationContext.publishEvent(new ConvertFileEvent(this, saveFile.getAbsolutePath()));
                    // H5课件
                    if (file.getOriginalFilename().endsWith(".zip")) {
                        FileUtils.unZipFiles(uploadPath + newFilename, uploadPath+newFilename.split("\\.")[0]);
                        result.put("filePath","/" + relativePath + newFilename.split("\\.")[0] + "/index.html");
                    }
                    return new AjaxResult(AjaxResultConstant.Result.SUCCESS, "", result);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                    return new AjaxResult(AjaxResultConstant.Result.ERROR, e.getMessage());
                } catch (IOException e) {
                    e.printStackTrace();
                    return new AjaxResult(AjaxResultConstant.Result.ERROR, e.getMessage());
                }
            } else {
                return new AjaxResult(AjaxResultConstant.Result.ERROR, "文件为空");
            }
        } catch (Exception ex) {
            return new AjaxResult(AjaxResultConstant.Result.ERROR, "上传失败");
        }
    }

    /**
     * 多文件上传
     *
     * @param files
     * @param request
     * @return
     */
    @ApiOperation(value = "多文件上传", notes = "多文件上传")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "files", value = "文件", required = true, dataType = "MultipartFile"),
    })
    @PostMapping("/uploadFiles")
    public AjaxResult upload(@RequestParam("files") MultipartFile[] files, HttpServletRequest request) {
        List<JSONObject> fileRes = new ArrayList<>();
        try {
            for (MultipartFile file : files) {
                JSONObject result = new JSONObject();
                boolean flag = true;

                if (!file.isEmpty()) {
                    String md5 = request.getParameter("md5");
                    FileListBean fileList = null;
                    if (!StringUtils.isEmpty(md5)) {
                        fileList = fileListService.queryFileList(md5);
                        if (fileList != null && xhProperties.getUpload().getCheckMd5()) {
                            String filePath = request.getSession().getServletContext().getRealPath("/");
                            String relativePath = fileList.getFilePath();
                            filePath += relativePath;
                            File oldFile = new File(filePath);
                            if (oldFile.exists()) {
                                result.put("originalFilename", file.getOriginalFilename());
                                result.put("savePath", fileList.getFilePath());
                                fileRes.add(result);
                                continue;
                            }
                        }
                    }

                    String uploadPath = request.getSession().getServletContext().getRealPath("/");
                    String relativePath = "upload" + "/";
                    String customPath = request.getParameter("path");
                    if (!StringUtils.isEmpty(customPath)) {
                        relativePath += customPath + "/";
                    }
                    Date now = new Date();
                    relativePath += DateUtils.format(now, "yyyyMM") + "/";
                    relativePath += DateUtils.format(now, "dd") + "/";

                    String newFilename = FileUtils.randomRenameFilename(file.getOriginalFilename());

                    uploadPath += relativePath;
                    result.put("originalFilename", file.getOriginalFilename());
                    result.put("savePath", "/" + relativePath + newFilename);

                    File saveFile = new File(uploadPath, newFilename);
                    if (!saveFile.getParentFile().exists()) {
                        saveFile.getParentFile().mkdirs();
                    }
                    try {
                        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(saveFile));
                        //out.write(file.getBytes());
                        InputStream is = file.getInputStream();
                        byte[] buffer = new byte[1024];
                        int i = -1;
                        while ((i = is.read(buffer)) != -1) {
                            out.write(buffer, 0, i);
                        }
                        out.flush();
                        out.close();

                        result.put("fileSize", file.getSize());
                        try {
                            if (!StringUtils.isEmpty(md5)) {
                                if (fileList == null) {
                                    fileList = new FileListBean();
                                    fileList.setOriFilename(file.getOriginalFilename());
                                    fileList.setFileMd5(md5);
                                    fileList.setExt(Files.getFileExtension(file.getOriginalFilename().toLowerCase()));
                                    fileList.setFileSize(file.getSize());
                                    fileList.setFilePath("/" + relativePath + newFilename);
                                    fileListService.insertObj(fileList);
                                } else {
                                    fileList.setOriFilename(file.getOriginalFilename());
                                    fileList.setFileMd5(md5);
                                    fileList.setExt(Files.getFileExtension(file.getOriginalFilename().toLowerCase()));
                                    fileList.setFileSize(file.getSize());
                                    fileList.setFilePath("/" + relativePath + newFilename);
                                    fileListService.updateObj(fileList);
                                }
                            }
                        } catch (Exception ex) {

                        }
                        applicationContext.publishEvent(new ConvertFileEvent(this, saveFile.getAbsolutePath()));

                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                        flag = false;
                        result.put("msg", "文件未找到");
                    } catch (IOException e) {
                        e.printStackTrace();
                        flag = false;
                        result.put("msg", "系统磁盘问题，请联系管理员");
                    }
                } else {
                    flag = false;
                    result.put("msg", "文件为空");
                }
                result.put("isOk", flag);
                fileRes.add(result);
            }
        } catch (Exception ex) {
            return new AjaxResult(AjaxResultConstant.Result.ERROR, "上传失败");
        }
        return new AjaxResult(AjaxResultConstant.Result.SUCCESS, "", fileRes);
    }


    @ApiOperation(value = "文件下载", notes = "文件下载")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "url", value = "文件路径", required = true, dataType = "String"),
            @ApiImplicitParam(name = "filename", value = "下载后文件名", required = true, dataType = "String"),
    })
    @GetMapping("/download")
    public ResponseEntity<byte[]> download(String url, String filename, HttpServletRequest request, HttpServletResponse response) {
        try {
            HttpHeaders headers = new HttpHeaders();
            File file = new File(request.getSession().getServletContext().getRealPath("") + url);
            filename = (StringUtils.isEmpty(filename) ? file.getName() : filename);
            filename = URLDecoder.decode(filename, "UTF-8");
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            headers.setContentDispositionFormData("attachment", filename);
            if (file.exists()) {
                InputStream fis = new BufferedInputStream(new FileInputStream(file));   //用BufferedInputStream读取文件
                response.reset();
                response.setContentType("application/x-download");
                response.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes(), "iso-8859-1"));
                response.addHeader("Content-Length", "" + file.length());
                OutputStream os = new BufferedOutputStream(response.getOutputStream());
                response.setContentType("application/octet-stream");
                byte[] buffer = new byte[1024];
                int i = -1;
                while ((i = fis.read(buffer)) != -1) {   //不能一次性读完，大文件会内存溢出（不能直接fis.read(buffer);）
                    os.write(buffer, 0, i);

                }
                fis.close();
                os.flush();
                os.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @ApiOperation(value = "获取文件纯文本内容", notes = "获取文件纯文本内容")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "url", value = "文件路径", required = true, dataType = "String"),
    })
    @PostMapping("/textContent")
    public AjaxResult textContent(String url, HttpServletRequest request, HttpServletResponse response) {
        try {
            HttpHeaders headers = new HttpHeaders();

            if (url.startsWith("http:") || url.startsWith("https:")) {
                OutputStream os = new BufferedOutputStream(response.getOutputStream());
                String result = HttpClient.get(url).asString();
                return new AjaxResult(AjaxResultConstant.Result.SUCCESS, "", result);
            } else {
                File file = new File(request.getSession().getServletContext().getRealPath("") + url);
                if (file.exists()) {
                    List<String> result = Files.readLines(file, Charsets.UTF_8);
                    StringBuffer sb = new StringBuffer();
                    for (String s : result) {
                        sb.append(s).append("<br/>");
                    }
                    return new AjaxResult(AjaxResultConstant.Result.SUCCESS, "", sb.toString());
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return new AjaxResult(AjaxResultConstant.Result.ERROR, "");
    }


}
